package com.easy.utils;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;

public class CommonUtils {

    /**
     * 列表数据添加额外信息的通用函数式方法
     *
     * @param list     原始列表
     * @param getId    获取原始列表”主键id“的方法（唯一，重复时将不能遍历完整的list列表）
     * @param getMeta  获取额外信息的方法（一般是从数据库中获取数据）
     * @param consumer 设置参数
     * @param <K>      ”主键id“类型
     * @param <V>      集合类型
     * @param <T>      额外信息类型
     */
    public static <K, V, T> void listSetMetaInfo(Collection<V> list,
                                                 Function<V, K> getId,
                                                 Function<Collection<K>, List<T>> getMeta,
                                                 BiConsumer<T, Map<K, V>> consumer) {
        if (list.isEmpty()) return;
        List<K> ids = new ArrayList<>();
        Map<K, V> mapping = new HashMap<>();
        for (V k : list) {
            ids.add(getId.apply(k));
            mapping.put(getId.apply(k), k);
        }
        List<T> metaInfos = getMeta.apply(ids);
        for (T t : metaInfos) {
            consumer.accept(t, mapping);
        }
    }

    /**
     * 列表数据添加额外信息的通用函数式方法。
     * 与上面的方法不同的是：该方法遍历list列表，保证列表中的每个元素都能拿到需要填充的值（如果有的话）
     *
     * @param list     列表
     * @param getId    可以是第三方id，可以重复
     * @param getMeta  通过getId的值，获取额外信息列表 表达式
     * @param function 额外信息转换成map 表达式
     * @param consumer 设置额外信息 表达式
     */
    public static <K, V, T> void listSetMetaInfo(Collection<V> list,
                                                 Function<V, K> getId,
                                                 Function<Collection<K>, List<T>> getMeta,
                                                 Function<T, K> function,
                                                 BiConsumer<V, Map<K, T>> consumer) {
        if (list.isEmpty()) return;
        List<K> ids = StreamUtils.map(list, getId);
        List<T> metaInfos = getMeta.apply(ids);
        if (metaInfos.isEmpty()) return;
        Map<K, T> mapping = StreamUtils.toIdentityMap(metaInfos, function);
        for (V v : list) {
            consumer.accept(v, mapping);
        }
    }

    public static <K, V, T> void listSetMetaInfo(Map<K, V> map,
                                                 Function<Collection<K>, List<T>> getMeta,
                                                 BiConsumer<T, Map<K, V>> consumer) {
        if (map.isEmpty()) return;
        List<T> metaInfos = getMeta.apply(map.keySet());
        for (T t : metaInfos) {
            consumer.accept(t, map);
        }
    }

    /**
     * 如果集合中的某个属性为Null时，将该值设置为默认值
     *
     * @param list      集合
     * @param predicate 过滤方法
     * @param consumer  设置方法
     * @param e         默认值
     * @param <T>       集合类型
     * @param <E>       默认值类型
     */
    public static <T, E> void listSetDefaultValueIfNull(Collection<T> list, Predicate<T> predicate, BiConsumer<T, E> consumer, E e) {
        if (list.isEmpty()) return;
        List<T> filter = StreamUtils.filter(list, predicate);
        if (!filter.isEmpty()) {
            filter.forEach(item -> consumer.accept(item, e));
        }
    }

}
